package com.hexacta.hrs.test.data;

import java.io.Serializable;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.vectrics.common.db.CodedObject;
import org.vectrics.common.db.RecordObject;

/**
 * Abstract Class for TestDataDependencyCreator.
 * 
 * @see TestDataDependencyCreator
 * @author tpollak
 */
public abstract class AbstractTestDataDependencyCreator implements TestDataDependencyCreator {

    private DataUtils dataUtils;

    private final List<TestDataDependencyCreator> dependencies;

    private final DataCreatorHelper helper;

    private SessionFactory sessionFactory;

    public AbstractTestDataDependencyCreator(List<TestDataDependencyCreator> dependencies) {
        this.dependencies = Collections.unmodifiableList(dependencies);
        this.helper = new DataCreatorHelper();
    }

    public Set<Scenario> getApplicableScenarios() {
        // Default behavior: applies to all scenarios
        return EnumSet.allOf(Scenario.class);
    }

    public DataUtils getDataUtils() {
        return this.dataUtils;
    }

    public List<TestDataDependencyCreator> getDependencies() {
        return this.dependencies;
    }

    /**
     * @return the sessionFactory
     */
    public final SessionFactory getSessionFactory() {
        return this.sessionFactory;
    }

    public void setDataUtils(DataUtils dataUtils) {
        this.dataUtils = dataUtils;
    }

    /**
     * @param sessionFactory
     *            the sessionFactory to set
     */
    public final void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    protected final void flushSession() {
        new HibernateTemplate(this.getSessionFactory()).flush();
    }

    protected final Session getCurrentSession() {
        return this.getSessionFactory().getCurrentSession();
    }

    protected DataCreatorHelper getHelper() {
        return this.helper;
    }

    @SuppressWarnings("unchecked")
    protected final <T extends CodedObject> T insertCodedObject(T objectToInsert) {
        Serializable id = this.getCurrentSession().save(objectToInsert);
        return (T) this.getSessionFactory().getCurrentSession().load(objectToInsert.getClass(), id);
    }

    @SuppressWarnings("unchecked")
    protected final <T extends RecordObject> T insertDomainObject(T objectToInsert) {
        Serializable id = this.getCurrentSession().save(objectToInsert);
        return (T) this.getSessionFactory().getCurrentSession().load(objectToInsert.getClass(), id);
    }

    @SuppressWarnings("unchecked")
    protected final <T extends CodedObject> T loadCodedObjectFromContext(Map<String, Object> context, String key) {
        return (T) this.getHelper().loadObjectFromContext(context, key, this.getCurrentSession());
    }

    @SuppressWarnings("unchecked")
    protected final <T extends RecordObject> T loadObjectFromContext(Map<String, Object> context, String key) {
        return (T) this.getHelper().loadObjectFromContext(context, key, this.getCurrentSession());
    }

    protected final void storeCodedObjectReferenceInContext(Map<String, Object> context, String key, CodedObject object) {
        this.getHelper().storeObjectReferenceInContext(context, key, object);
    }

    protected final void storeObjectReferenceInContext(Map<String, Object> context, String key, RecordObject object) {
        this.getHelper().storeObjectReferenceInContext(context, key, object);
    }
}